#include "StdAfx.h"
#include "Scene.h"
#include "InfinitePlane.h"

Scene::Scene(void)
{
}


Scene::~Scene(void)
{
    for (size_t i = 0; i < m_objects.size(); ++i)
    {
        delete m_objects[i];
    }
    m_objects.clear();

    for (size_t i = 0; i < m_lights.size(); ++i)
    {
        delete m_lights[i];
    }
    m_lights.clear();

}

void Scene::Init()
{
    m_colorAmbient = ColorValue(0.5, 0.5, 0.5);

    // Init the light
    Light* pLight;

	pLight = new Light;	
    pLight->Init(Vector3f(-20, 20, 10), ColorValue(0.7, 0.7, 0.7));
    m_lights.push_back(pLight);

	pLight = new Light;
	pLight->Init(Vector3f(0, -20, 10), ColorValue(0.9, 0.9, 0.9));
	m_lights.push_back(pLight);

	pLight = new Light;
	pLight->Init(Vector3f(20, -20, 10), ColorValue(0.5, 0.5, 0.5));
	m_lights.push_back(pLight);

	Material mat = Material::Wall;
    RenderableObject* pObject;
/*	
    // 6 Big walls
    // up - right
	pObject = new Sphere;
	mat.SetColor(ColorValue(0, 0.8, 0.8));
	((Sphere*)pObject)->Init(Vector3f(1500, 1500, 0), 2000, mat);
	m_objects.push_back(pObject);

    // left - bottom
	pObject = new Sphere;
	mat.SetColor(ColorValue(0.1, 0.1, 0.1));
	((Sphere*)pObject)->Init(Vector3f(-1500, -1500, 0), 2000, mat);
	m_objects.push_back(pObject);

    // left - up
	pObject = new Sphere;
	mat.SetColor(ColorValue(0.6, 0, 0.6));
	((Sphere*)pObject)->Init(Vector3f(-1500, 1500, 0), 2000, mat);
	m_objects.push_back(pObject);

    // right - down
	pObject = new Sphere;
	mat.SetColor(ColorValue(1, 0.6, 0.6));
	((Sphere*)pObject)->Init(Vector3f(1500, -1500, 0), 2000, mat);
	m_objects.push_back(pObject);

    // near
	pObject = new Sphere;
	mat.SetColor(ColorValue(0.6, 0.6, 1));
	((Sphere*)pObject)->Init(Vector3f(0, 0, 3000), 2000, mat);
	m_objects.push_back(pObject);

    // far
	pObject = new Sphere;
	mat.SetColor(ColorValue(0.5, 0.5, 0.2));
	((Sphere*)pObject)->Init(Vector3f(0, 0, -3000), 2000, mat);
	m_objects.push_back(pObject);
*/

	// 5 small balls
    mat = Material::Air;
	/**/

	pObject = new Sphere;
    mat.SetColor(ColorValue(0.8, 0.0, 0.0));
	mat.SetAlpha(0.5);
	mat.SetRefractiveIndex(0.6);
	mat.SetReflectivity(0.5);
    ((Sphere*)pObject)->Init(Vector3f(-6, 7, -8), 5, mat);
    m_objects.push_back(pObject);

    pObject = new Sphere;
    mat.SetColor(ColorValue(0, 1, 0));
	mat.SetAlpha(1);
	mat.SetRefractiveIndex(1);
	mat.SetReflectivity(0.6);
    ((Sphere*)pObject)->Init(Vector3f(4, 6, -10), 5, mat);
    m_objects.push_back(pObject);


	pObject = new Sphere;
	mat.SetColor(ColorValue(0.2, 0.2, 0.7));
	mat.SetAlpha(0.8);
	mat.SetRefractiveIndex(0.5);
	mat.SetReflectivity(0.6);
	((Sphere*)pObject)->Init(Vector3f(10, -10, -1), 6, mat);
	m_objects.push_back(pObject);

	pObject = new Sphere;
	mat.SetColor(ColorValue(0.9, 0.4, 0.6));
	mat.SetAlpha(1);
	mat.SetRefractiveIndex(1);
	mat.SetReflectivity(0.6);
	((Sphere*)pObject)->Init(Vector3f(-7, -6, -5), 6, mat);
	m_objects.push_back(pObject);

	pObject = new Sphere;
	mat.SetColor(ColorValue(0.8, 0.8, 0.8));
    mat.SetAlpha(0.1);
	mat.SetRefractiveIndex(0.9);
	mat.SetReflectivity(0.9);
	((Sphere*)pObject)->Init(Vector3f(1, 1, 6), 6, mat);
	pObject->SetID(1);
	m_objects.push_back(pObject);


    // big plane
    pObject = new InfinitePlane;
    mat.SetColor(ColorValue(0.99, 0.99, 0.0));
    mat.SetAlpha(1);
    mat.SetRefractiveIndex(0.6);
    mat.SetReflectivity(0.1);
    ((InfinitePlane*)pObject)->Init(Vector3f(0, 0.5, 0.5), Vector3f(0, 0, -50), mat);
    m_objects.push_back(pObject);
}

std::vector<Light*>& Scene::GetLights(void)
{
	return m_lights;
}

bool Scene::Intersect(Line *pLine, IntersectInfo* pInfo)
{
    bool bIntersect = false;
    pInfo->pObject = NULL;
    IntersectInfo tempInfo;
    pInfo->fDistance = 99999;

    for (int i = 0; i < GetObjectNum(); ++i)
    {
        RenderableObject *pObject = GetObject(i);
        if(pObject->Intersect(pLine, &tempInfo))
        {
            if (tempInfo.fDistance < pInfo->fDistance)
            {
                // Always keep the nearest object.
                *pInfo = tempInfo;
                pInfo->pObject = pObject;
                bIntersect = true;
            }
        }
    }


    return bIntersect;
}

bool Scene::SegmentIntersect(Line *pLine)
{
    //return false;
    IntersectInfo tempInfo;
    for (int i = 0; i < GetObjectNum(); ++i)
    {
        RenderableObject *pObject = GetObject(i);
        if(pObject->Intersect(pLine, &tempInfo))
        {
            if (tempInfo.fDistance < pLine->GetLength())
            { 
                return true;
            }
           
        }
    }
    return false;
}